﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using CommonClasses.Utility;
using CommonClasses.Logger;

namespace IDEDialogs
{
    //диалог позволяет задать параметры нового проекта
    //проверка путей на корректность вызывается только при нажатии на OKButton (а не при потере полем ввода фокуса)
    //механизм проверки на основе сообщения - http://www.rsdn.ru/Forum/?mid=2763832
    public partial class NewProjectDialog : Form
    {
        #region Поля, доступные извне (результаты работы дилога)
        /// <summary>
        /// Путь до файла с проектом
        /// </summary>
        public string ProjectFolderPath;

        /// <summary>
        /// Имя проекта
        /// </summary>
        public string ProjectName;

        /// <summary>
        /// Путь до файла с описанием оборудования
        /// </summary>
        public string DomainModelPath;

        /// <summary>
        /// Тип проекта
        /// </summary>
        public Project.Model.ProjectType ProjectType;
        #endregion

        /// <summary>
        /// Путь до файла с оборудованием по умолчанию
        /// </summary>
        private string defPrjDir;

        /// <summary>
        /// Известные приложению файлы с описанием оборудования
        /// </summary>
        private List<string> knownDomModels = new List<string>();

        /// <summary>
        /// Список всех типов проектов
        /// </summary>
        private List<Project.Model.ProjectType> projectTypes = new List<Project.Model.ProjectType>();

        /// <summary>
        /// Логгер
        /// </summary>
        private ILogger logger = null;

        /// <summary>
        /// Конструктор диалога для открытия нового проекта
        /// </summary>
        /// <param name="defPrjDir">Путь по умолчанию к папке с проектами</param>
        /// <param name="defDomModDir">Путь по умолчанию к папке с описаниями оборудования</param>
        /// <param name="loggingManagment">Среда для создания собственного лога</param>
        public NewProjectDialog(string defPrjDir, string defDomModDir, ILoggingManagement loggingManagment)
        {
            this.logger = loggingManagment.GetLogger("NewProjectDialog_Logger");

            InitializeComponent();

            PathUtility.RestoreCurrentDirectory(Locality.ExeFile);

            this.defPrjDir = defPrjDir;
            // по умолчанию проект сохраняется в папку по умолчанию
            if (!Directory.Exists(defPrjDir))
                Directory.CreateDirectory(defPrjDir);

            // по умолчанию предложится список файлов с описанием обродования из 
            // соответствующей папки по умлочнию defDomModDir 
            if (Directory.Exists(defDomModDir))
                knownDomModels = new List<string>(Directory.GetFiles(defDomModDir, "*.main.ihdm", SearchOption.AllDirectories));
            else
                ErrorsUtility.FatalError("Error at NewProjectDialog: default DomainModel directory does not exists", logger);

            DirPrjTextBox.Text = this.defPrjDir;
            foreach (var model in knownDomModels)
                DomainModelCtrlBox.Items.Add(model);

            // устанавливаем список типов проекта
            cboxProjectType.Items.Add("Обычный");
            projectTypes.Add(Project.Model.ProjectType.Usual);
            cboxProjectType.Items.Add("Списки команд");
            projectTypes.Add(Project.Model.ProjectType.CommandList);
            cboxProjectType.SelectedIndex = 1;
            ProjectType = projectTypes[cboxProjectType.SelectedIndex];

            if (DomainModelCtrlBox.Items.Count != 0)
                DomainModelCtrlBox.SelectedIndex = 0;
            else DomainModelCtrlBox.SelectedIndex = -1;

            DirPrjTextBox_Validated(null, null);
            NamePrjTextBox_Validated(null, null);

            NamePrjTextBox.Select(); // фокус на ввод имени
        }

        /// <summary>
        /// Обработчик нажатия на кнопку "Выбор директории проекта"
        /// </summary>
        /// <param name="sender">sender</param>
        /// <param name="e">EventArgs</param>
        private void BrowseButton_Click(object sender, EventArgs e)
        {
            PathUtility.RestoreCurrentDirectory(Locality.ExeFile);
            FolderBrowserDialog fbd = new FolderBrowserDialog();
            fbd.Description = "Выберите директорию в которой будет создан файл проекта. При этом все файлы проекта будут также сохраняться в этой директории";
            fbd.ShowNewFolderButton = true;
            fbd.SelectedPath = Path.GetFullPath(ProjectFolderPath);
            DialogResult r = fbd.ShowDialog();

            //диалог мог изменить CurrentDirectory
            PathUtility.RestoreCurrentDirectory(Locality.ExeFile);

            if (r == DialogResult.OK)
            {
                DirPrjTextBox.Text = fbd.SelectedPath;
                //поскольку мы меняем содержимое DirPrjTextBox из кода, 
                //то должны послать сообщение Validating - эмулируем смену фокуса
                DirPrjTextBox.Focus();
                BrowseButton.Focus();
            }
        }

        /// <summary>
        /// Обработчик для проверки правильности при изменения пути до файла с проектом
        /// </summary>
        /// <param name="sender">sender</param>
        /// <param name="e">CancelEventArgs</param>
        private void DirPrjTextBox_Validating(object sender, CancelEventArgs e)
        {
            string path = DirPrjTextBox.Text.Trim();
            int indx = path.IndexOfAny(Path.GetInvalidPathChars());
            if (indx > 0)
            {
                errorProvider1.SetError(DirPrjTextBox, "Имя директории не может содержать символ: " + path[indx]);
                e.Cancel = true;
            }
            if (path == "")
            {
                errorProvider1.SetError(DirPrjTextBox, "Имя директории должно быть задано");
                e.Cancel = true;
            }
            this.defPrjDir = path;

        }

        /// <summary>
        /// Обработчик для проверки правильности после изменения пути до файла с проектом
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void DirPrjTextBox_Validated(object sender, EventArgs e)
        {
            ProjectFolderPath = DirPrjTextBox.Text.Trim();
            if (!ProjectFolderPath.EndsWith("\\"))
                ProjectFolderPath = ProjectFolderPath.Insert(ProjectFolderPath.Length, "\\");
            ProjectFolderPath += ProjectName + "\\";
            PathUtility.MakePathLocal(ProjectFolderPath, Locality.ExeFile);
            errorProvider1.SetError(DirPrjTextBox, null);
        }

        /// <summary>
        /// Обработчик для проверки правильности при изменении имени проекта
        /// </summary>
        /// <param name="sender">sender</param>
        /// <param name="e">CancelEventArgs</param>
        private void NamePrjTextBox_Validating(object sender, CancelEventArgs e)
        {
            string name = NamePrjTextBox.Text.Trim();
            int indx = name.IndexOfAny(Path.GetInvalidFileNameChars());
            if (indx > 0)
            {
                errorProvider1.SetError(NamePrjTextBox, "Имя файла не может содержать символ: " + name[indx]);
                e.Cancel = true;
            }
            if (name == "")
            {
                errorProvider1.SetError(NamePrjTextBox, "Имя файла должно быть задано");
                e.Cancel = true;
            }
            if (!e.Cancel)
                ProjectName = name;

        }

        /// <summary>
        /// Обрабочик для проверки правильности после изменения имени проекта
        /// </summary>
        /// <param name="sender">sender</param>
        /// <param name="e">EventArgs</param>
        private void NamePrjTextBox_Validated(object sender, EventArgs e)
        {
            ProjectName = NamePrjTextBox.Text.Trim();
            errorProvider1.SetError(NamePrjTextBox, "");
        }

        /// <summary>
        /// Обработчик нажатия на кнопку "Выбор файла с описанием оборудования"
        /// </summary>
        /// <param name="sender">sender</param>
        /// <param name="e">EventArgs</param>
        private void BrowseButton2_Click(object sender, EventArgs e)
        {
            OpenFileDialog dial = new OpenFileDialog();

            dial.AddExtension = true;
            dial.CheckFileExists = true;
            dial.Multiselect = false;
            dial.SupportMultiDottedExtensions = false;
            dial.DefaultExt = "Описание оборудования (*.main.ihdm) | *.main.ihdm";
            dial.Filter = "Описание оборудования (*.main.ihdm) | *.main.ihdm";
            dial.RestoreDirectory = true;
            DialogResult res = dial.ShowDialog();

            if (res == DialogResult.OK)
            {
                string dmPath = PathUtility.MakePathLocal(dial.FileName, Locality.ExeFile);
                if (!File.Exists(dmPath))
                {
                    errorProvider1.SetError(DomainModelCtrlBox, "Данный файл не существует");
                    ErrorsUtility.Error("Файла с описанием оборудования не существует", logger);
                }
                else DomainModelPath = dmPath;

                DomainModelCtrlBox.Text = DomainModelPath;
                //поскольку мы меняем содержимое DomainModelCtrlBox из кода, 
                //то должны послать сообщение Validating - эмулируем смену фокуса
                DomainModelCtrlBox.Focus();
                BrowseButton2.Focus();
            }

        }

        /// <summary>
        /// Обработчик для проверки правильности при выборе файла из списка файлов описания оборудования
        /// </summary>
        /// <param name="sender">sender</param>
        /// <param name="e">CancelEventArgs</param>
        private void DomainModelCtrlBox_Validating(object sender, CancelEventArgs e)
        {
            string modelpath = DomainModelCtrlBox.Text.Trim();

            if (!File.Exists(modelpath))
            {
                errorProvider1.SetError(DomainModelCtrlBox, "Данный файл не существует");
                e.Cancel = true;
            }
            if (modelpath == "")
            {
                errorProvider1.SetError(DomainModelCtrlBox, "Имя файла должно быть задано");
                e.Cancel = true;
            }

            if (!e.Cancel)
                DomainModelPath = modelpath;
        }

        /// <summary>
        /// Обработчик для проверки правильности после выбора файла из списка файлов описания оборудования
        /// </summary>
        /// <param name="sender">sender</param>
        /// <param name="e">EventArgs</param>
        private void DomainModelCtrlBox_Validated(object sender, EventArgs e)
        {
            DomainModelPath = DomainModelCtrlBox.Text.Trim();
            errorProvider1.SetError(DomainModelCtrlBox, "");
        }

        /// <summary>
        /// Обрабочик изменения индекса выбираемого типа проекта
        /// </summary>
        /// <param name="sender">sender</param>
        /// <param name="e">EventArgs</param>
        private void cboxProjectType_SelectedIndexChanged(object sender, EventArgs e)
        {
            ProjectType = projectTypes[cboxProjectType.SelectedIndex];
        }

        /// <summary>
        /// Запрос о возможности закрытия окна диалога
        /// </summary>
        /// <returns>(bool) Можно ли закрыть данное окно данного диалога</returns>
        private bool CanClose()
        {
            if (File.Exists(this.ProjectFolderPath + "\\" + this.ProjectName + ".ihprj"))
            {
                DialogResult res = MessageBox.Show("Файл проекта" + this.ProjectFolderPath + "\\" + this.ProjectName + ".ihprj"
                                       + " уже существует. Переписать его?", "Подтверждение", MessageBoxButtons.OKCancel, MessageBoxIcon.Question);
                if (res == DialogResult.Cancel)
                    return false;
                else return true;
            }
            else return true;
        }

        /// <summary>
        /// Обрабочик нажатия на кнопку OK
        /// </summary>
        /// <param name="sender">sender</param>
        /// <param name="e">EventArgs</param>
        private void OKButton_Click(object sender, EventArgs e)
        {
            DirPrjTextBox_Validated(null, null);
            NamePrjTextBox_Validated(null, null);

            if (!ValidateChildren())
                DialogResult = DialogResult.None; // Валидация прошла неуспешно, отменяем закрытие формы  
            else if (!CanClose())
                DialogResult = DialogResult.None; // Валидация прошла неуспешно, отменяем закрытие формы  
        }
    }

}
